<?php

	error_reporting(CORMO_ERROR);

  require_once "Access.class.php";
  require_once "Object.class.php";
  require_once "Message.class.php";
  require_once 'Debug.class.php';

   /**
    * La finalidad es lograr contener todos aquellos metodos que son comunes a todo tipo
    * de Objeto, pero que a su vez no es necesario que esten en cada uno de ellos, como
    * por ejemplo lo relacionado a Busquedas masivas. Dependiendo de quien heredo sera
    * la Logica de Negocio a consultar, pero los metodos que se encargan de ellos son
    * exactamente iguales para cualquier objeto del sistema e incluirlos en cada objeto
    * instanciado seria un de desperdicio de recursos.
    *
    * @category cormo
    * @package Core
    * @author Germán Dario Peraferrer <gperaferrer@gmail.com>
    * @copyright Copyright (c) 2007 Germán Dario Peraferrer - Beetec
    * @version 1.0 Beta
    * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
    * @link http://code.google.com/p/cormoframework/
    * @link http://www.beetec.com.ar
  	*/

    abstract class Peer {

        /**
         * Composicion: Instacia de Access
         *
         * @var Access
         */
        private static $cnxPDO;

        /**
         * Composicion: Instancia de Message
         *
         * @var Message
         */
        private static $Message;

        /**
         * Composicion: creamos un objeto Config para poder manipular el objeto a Persistir
         *
         * @var Config
         */
        private static $config;

        /**
         * Creamos el Objeto de Persistencia el cual sera utilizado para poder
         * crear los Objetos del Modelo del Negocio y administrar su Persistencia.
         *
         * @return void
         */
        protected static function init($nameObjectORM) {
            Debug::captureBackTrace();
            self::$Message = new Message();
            self::$config = new Object($nameObjectORM);

            if (self::$config->isConfigValid())	{
                try  {
                    // Recuperamos la Instacia de la Conexion a la Base de Datos
                    self::setConnection(new Access(self::getConfig()->getConnection()));
        	    } catch(PDOException $e) {
                    die("Persist Error: No se ha podido crear el Objeto PDO.<br>".$e->getMessage());
                }
            } else	{
                self::Message()->setMessage("Peer: Error la configuracion de ORM del Objeto a Persistir no se encuentra completa.");
            }
        }

        /**
         * Obtenemos un Objeto de tipo Connection con la configuracion de la Conexion del Driver
         *
         * @return Object
         */
        public static function getConfig()  {
           return self::$config;
        }

        /**
         * Guardamos la Instancia de la Conexion a la Base de Datos.
         *
         * @param PDO $pdo
         * @return void;
         */
        private static function setConnection($pdo)  {
            self::$cnxPDO = $pdo;
        }

        /**
         * Obtenemos la instacia de la Conexion PDO a la Base de Datos.
         *
         * @return Access
         */
        protected static function getConnection()  {
            return self::$cnxPDO;
        }

        /**
         * Devuelve el la Instacia del Manejador de Mensajes para Persist
         *
         * @return Message
         */
        protected static function Message()	{
            return self::$Message;
        }

       /**
        * Obtiene elUltimo Mensaje de Persist y se implementa para que las Class
        * que heredan de Persist puedan obtene el Ultimo Mensaje.
        *
        * @return string
        */
       protected static function getMessage()	{
           return self::Message()->getMessage();
       }

       /**
        * Obtenemos un ArryaObject con todos los objetos de la Tabla correspondiente al objeto
        * que nos ha heredado, para luego devolver un Iterator de los objetos encontrados.
        *
        * @return ArrayObject
        */
        protected static function getObjectsAll()  {
            Debug::captureBackTrace();
            if(Access::isConnected())  {

                try {
                    // Creamos el SELECT con el ID para luego ser retornado en caso de que el Objeto exista
                    //$sql = 'SELECT '.self::$config->getConfigTableName().'.'.self::$config->getConfigKey();
                    $sql = 'SELECT';
                    foreach(self::$config->getConfigFields() as $key => $value) {
                        // Verificamos si el field actual debe utilizar alguna function particular de SQL
                        if (array_key_exists($value, self::getConfig()->getFunctionsSQL())) {
                            // Obtenemos la function que debe ser utilizada junto a este Field
                            $arr = self::getConfig()->getFunctionsSQL();
                            $tmpFunction = $arr[$value];
                            $sql .= ' '.$tmpFunction.' as '.$value.',';
                        } else {
                            $sql .= ' '.self::getConfig()->getConfigTableName().'.'.$value.',';
                        }
//                        $sql .= ' '.self::$config->getConfigTableName().'.'.$value.',';
                    }

                    // Eliminamos la Ultima Coma
                    $sql = substr($sql, 0, strlen($sql)-1);

                    // Especificamos en que tabla se buscaran los datos
                    $sql .= ' FROM '.self::$config->getConfigTableName();

                    // Preparamos la Consulta
                    $sth = self::getConnection()->prepare($sql);

                    if($sth->execute()) {
                        // Devolvemos el Key del Registro ya existente
                        $result = $sth->fetchAll(PDO::FETCH_ASSOC);

                        // Obtenemos el nombre de la class que nos ha heradado, para luego poder crear el objeto
                        $name_class = self::$config->getConfigObjectName();

                        // Aqui se guardaran cada uno de los objetos que se van recuperando
                        $arrObj = new ArrayObject();

                        // Vamos agragando los Objetos al Conetendor
                        foreach($result as $value)  {
                            $tmpNewObject = new $name_class();
                            $tmpNewObject->loadArray($value);
                            $arrObj->append($tmpNewObject);
                            //$arrObj->append(new $name_class($value));
                        }

                        // Retornamos el Iterator
                        return $arrObj->getIterator();

                    } else {
                        self::Message()->setMessage("Persist [".@get_class($this)."] - ERROR: <pre>".print_r($sth->errorInfo(), true)."</pre>");
                        return null;
                    }

                } catch(PDOException $e)  {
                    self::Message()->setMessage("Persist [".@get_class($this)."] - ERROR: " . $e->getMessage() . "<br/>");
                    return false;
                }

             } else  {
                 self::Message()->setMessage("Persist Error: No estamos conectado con la Base de Datos.");
                 return false;
             }
        }

        /**
         * Obtiene los Objetos por su Primary Key, le podemos pasar un Array con una lista de ellos
         * para asi lograr obtener muchos objetos.
         *
         * Recibe como parametro un Array con los PKs, pero en caso de buscar uno solo, podemos pasarlo
         * como si se tratara de un Int comun, internamente se creara el Array con un solo elemento.
         *
         * @param array $pks
         * @return ArrayObject
         */
        protected static function getObjectsByPK($pks) {
            Debug::captureBackTrace();
            if(Access::isConnected())  {

               try {

                    // Preparamos la seleccion de registros para luego formar el Select
                    $sql = 'SELECT';
                    foreach(self::$config->getConfigFields() as $key => $value) {
                        // Verificamos si el field actual debe utilizar alguna function particular de SQL
                        if (array_key_exists($value, self::getConfig()->getFunctionsSQL())) {
                            // Obtenemos la function que debe ser utilizada junto a este Field
                            $arr = self::getConfig()->getFunctionsSQL();
                            $tmpFunction = $arr[$value];
                            $sql .= ' '.$tmpFunction.' as '.$value.',';
                        } else {
                            $sql .= ' '.self::getConfig()->getConfigTableName().'.'.$value.',';
                        }
                    }

                    // Eliminamos la Ultima Coma
                    $sql = substr($sql, 0, strlen($sql)-1);

                    /*
                     * Preparamos el FROM del SELECT que se utilizara para ubicar el registro que posee
                     * los valores que le seran asignados a la Class que nos ha Heredado.
                     */
                    $sql .= ' FROM '.self::$config->getConfigTableName();

                    /*
                     * Preparamos el WHERE del SELECT que utilizaremos para localizar los valores del
                     * Class que nos ha HEredado.
                     */
                    $sql .= ' WHERE ';

                    /**
                     * Verificamos si se trata de un Array, en caso de no serlo, lo convertimos para poder utilizarlo
                     * durante la consulta
                     */
                    if (!is_array($pks)) {
                        $pks = array($pks);
                    }

                    // Preparamos las condicionales para realizar la busqueda
                    foreach ($pks as $key => $value) {
                        $sql .= ' ('.self::$config->getConfigTableName().'.'.self::$config->getConfigKey().' = ?) OR';
                    }

                    // Eliminamos el Ultima OR
                    $sql = substr($sql, 0, strlen($sql)-2);

                    // Preparamos la Consulta
                    $sth = self::getConnection()->prepare($sql);

                    // Pasamos como parametro el Array con los Valores de los PK a Buscar
                    if($sth->execute($pks)) {
                        // Devolvemos el Key del Registro ya existente
                        $result = $sth->fetchAll(PDO::FETCH_ASSOC);

                        // Aqui se guardaran cada uno de los objetos que se van recuperando
                        $arrObj = new ArrayObject();

                        // Obtenemos el nombre de la class que nos ha heradado, para luego poder crear el objeto
                        $name_class = self::$config->getConfigObjectName();

                        // Vamos agragando los Objetos al Conetendor
                        foreach($result as $key => $value)  {
                            $tmpNewObject = new $name_class();
                            $tmpNewObject->loadArray($value);
                            $arrObj->append($tmpNewObject);
                            //$arrObj->append(new $name_class($value));
                        }

                        // Retornamos el Iterator
                        return $arrObj->getIterator();

                    } else {
                        self::Message()->setMessage("Persist [".@get_class($this)."] - ERROR: <pre>".print_r($sth->errorInfo(), true)."</pre>");
                        return false;
                    }

                } catch(PDOException $e)  {
                    self::Message()->setMessage("Persist [".@get_class($this)."] - ERROR: " . $e->getMessage() . "<br/>");
                    return false;
                }

            } else  {
                self::Message()->setMessage("Persist Error: No estamos conectado con la Base de Datos.");
                return false;
            }

       }

        /**
         * Realiza una busqueda de los objetos que poseen los valores expresados en las properties
         * solo funciona con loas properties del mismo objeto.
         *
         * @param array $properties
         * @return ArrayObject
         */
        protected static function getObjectsByProperty($properties) {
            Debug::captureBackTrace();
            if(Access::isConnected())  {

            try {

                // Preparamos la seleccion de registros para luego formar el Select
                $sql = 'SELECT';
                foreach(self::$config->getConfigFields() as $key => $value) {
                    // Verificamos si el field actual debe utilizar alguna function particular de SQL
                    if (array_key_exists($value, self::getConfig()->getFunctionsSQL())) {
                        // Obtenemos la function que debe ser utilizada junto a este Field
                        $arr = self::getConfig()->getFunctionsSQL();
                        $tmpFunction = $arr[$value];
                        $sql .= ' '.$tmpFunction.' as '.$value.',';
                    } else {
                        $sql .= ' '.self::getConfig()->getConfigTableName().'.'.$value.',';
                    }
                }

                // Eliminamos la Ultima Coma
                $sql = substr($sql, 0, strlen($sql)-1);

               /*
                * Preparamos el FROM del SELECT que se utilizara para ubicar el registro que posee
                * los valores que le seran asignados a la Class que nos ha Heredado.
                */
               $sql .= ' FROM '.self::$config->getConfigTableName();

               /*
                * Preparamos el WHERE del SELECT que utilizaremos para localizar los valores del
                * Class que nos ha HEredado.
                */
               $sql .= ' WHERE ';

               /**
                * Verificamos si se trata de un Array, en caso de no serlo, lo convertimos para poder utilizarlo
                * durante la consulta
                */
               if (!is_array($properties)) {
                   $properties = array($properties);
               }

               // Creamos el array que contiene los valores de los campos que sera utilizados como filtro en el SQL
               $arrValueProperties = array();

               // Preparamos las condicionales para realizar la busqueda
               foreach ($properties as $field => $value)	{
                    // Preparamos el condicional del SQL
					$sql .= ' ('.self::$config->getConfigTableName().'.'.$field.' '.$value[1].' ? ) '.$value[2];

					// Vamos completando el Array que sera pasado con los valores para reemplazar por ? en execute
                    array_push($arrValueProperties, $value[0]);
               }

               // Preparamos la Consulta
               $sth = self::getConnection()->prepare($sql);

               // Pasamos como parametro el Array con los Valores de los PK a Buscar
               if($sth->execute($arrValueProperties)) {
                    // Devolvemos el Key del Registro ya existente
                    $result = $sth->fetchAll(PDO::FETCH_ASSOC);

                    // Aqui se guardaran cada uno de los objetos que se van recuperando
                    $arrObj = new ArrayObject();

                    // Obtenemos el nombre de la class que nos ha heradado, para luego poder crear el objeto
                    $name_class = self::$config->getConfigObjectName();

                    // Vamos agragando los Objetos al Contendor
                    foreach($result as $value)  {
                        $tmpNewObject = new $name_class();
                        $tmpNewObject->loadArray($value);
                        $arrObj->append($tmpNewObject);
                        //$arrObj->append(new $name_class($value));
                    }

                    // Retornamos el Iterator
                    return $arrObj->getIterator();

                } else {
                    self::Message()->setMessage("Persist [".@get_class($this)."] - ERROR: <pre>".print_r($sth->errorInfo(), true)."</pre>");
                    return false;
                }

            } catch(PDOException $e)  {
                self::Message()->setMessage("Persist [".@get_class($this)."] - ERROR: " . $e->getMessage() . "<br/>");
                return false;
            }

        } else  {
             self::Message()->setMessage("Persist Error: No estamos conectado con la Base de Datos.");
            return false;
        }

    }


  }

?>